namespace QM {
    /** 地图数据 */
    export interface mapDat {
        npc?: Npc[]
        plot?: Db.Plot[]
        door?: Door[],
        item?:Item[]
    }

    /** Npc数据 */
    export interface Npc {
        /** 名字 */
        name: string
        /** 显示图 */
        texture: string
        /** 出生位置 */
        point?: string
        /** 移动路径(巡场走动) */
        path?:string
        /** 动作 */
        action: number
        /** 方向 */
        dir: QM.Dir
        /** 剧本 */
        plot?:Db.Plot[]
        /** 满足条件时,修改剧情
         * if  taskId 接受了ID任务 itemId 拥有某ID物品
         */
        needIf?:NeedIf
    }

    /** 满足某些条件，修改剧情 */
    export interface NeedIf{
        if:{
            taskId?:number
            itemId?:number
        }
        plot:Db.Plot[]
    }

    /** Door门数据结构 */
    export interface Door{
        name:string
        /** 进入的地图 */
        map?:string
        /** 是否开门 */
        isOpen?:boolean
        /** 门禁 */
        plot?:Db.Plot[]
    }
    
    /** 地图 物品数据 */
    export interface Item{
        itemId:number
        point:string
        /** 是否可以拾取 */
        isPickUp?:boolean
        show?:boolean
    }


    /** 方向 */
    export enum Dir {
        /** 上 */
        up = 1,
        /** 下 */
        down,
        /** 左 */
        left,
        /** 右 */
        right,
        /** 左上 */
        leftUp,
        /** 右下 */
        rightDown,
        /** 左下 */
        leftDown,
        /** 右上 */
        rightUp
    }

    export function getDirForAngle(angle:number){
        var dir:QM.Dir;
        if(angle>=-22.5 && angle<22.5){            
            dir = QM.Dir.right            
        }else if(angle>=22.5 && angle<67.5){            
            dir = QM.Dir.rightUp            
        }else if(angle>=67.5 && angle<112.5){            
            dir = QM.Dir.up            
        }else if(angle>=112.5 && angle<157.5){            
            dir = QM.Dir.leftUp            
        }else if( angle>=157.5 || angle<-157.5 ){          
            dir = QM.Dir.left          
        }else if( angle>=-157.5 && angle<-112.5){            
            dir = QM.Dir.leftDown            
        }else if( angle>=-112.5 && angle<-67.5){            
            dir = QM.Dir.down            
        }else if(angle>=-67.5 && angle<-22.5){            
            dir = QM.Dir.rightDown           
        }       
        return dir as number; 
    }

    /**
     * 队友
     */
    export interface Player {
        /** 名称 */
        name: string
        /** 图源 */
        texture: string
        /** 动作 */
        action: number
        /** 方向 */
        dir: QM.Dir
        /** 编号 1号为队长 */
        number:number
        /** 坐标 */
        position:{x:number,y:number}
        attr: {
            /** 等级 */
            level: number
            /** 当前经验 */
            exp: number
            /** 体力 */
            hp: {
                /** 当前体力 */
                current: number
                /** 最大体力 */
                max: number
            }
            /** 真气 */
            mp: {
                /** 当前真气 */
                current: number
                /** 最大真气 */
                max: number
            }
            /** 物理攻击力 武术 */
            physical: number
            /** 魔法攻击力 灵力 */
            magic: number
            /** 防御 */
            defense: number
            /** 身法 */
            bodylaw: number
            /** 吉运 */
            luck: number
        }
        /** 装备 */
        equipment : {
            /** 帽子 */
            hat: number
            /** 披风护肩 */
            cloak: number
            /** 衣服 */
            clothes: number
            /** 武器 */
            arms: number
            /** 佩带 */
            wear: number
            /** 鞋子 */
            shoes: number
        }
    }

    /** 背包物品 */
    export interface PackItem{
        [id:number]:number
    }    

    /** 事件 */
    export interface QEvent{
        name:string
        data:any
    }

    /** 游戏状态 */
    export enum gameState{
        /** 正常 */
        normal=1,
        /** 剧本控制中  */
        Plot
    }

    export class Game {                
        private static readonly Instance: Game = new Game;
        
        private _events:{
            [key:string]:{func:any,obj:any}
        }={}

        /** 游戏状态
         * normal:正常 
         * UI:UI显示中
        */
        state:gameState = gameState.normal
        /** 当前地图 */
        map: string = "杭州城";
        gameTime:number=0;
        /** 上次进入过的门 */
        door:string;
        /** 地图信息 */
        private mapDat: { [key: string]: mapDat } = {}
        /** 队伍信息 */
        private team:Player[] = [
            {
                name:"王小虎",
                texture:"base",
                action:1,
                dir:QM.Dir.down,
                number:1,
                position:{x:1145,y:158},
                attr:{
                    level:1,
                    exp:0,
                    hp:{
                        current:150,
                        max:150
                    },
                    mp:{
                        current:100,
                        max:100
                    },
                    physical:31,
                    magic:25,
                    defense:23,
                    bodylaw:30,
                    luck:20
                },
                equipment:{
                    hat:200,
                    cloak:400,
                    clothes:500,
                    arms:1,
                    wear:600,
                    shoes:800
                }
            }
        ]
        /** 背包物品 */
        private pack:PackItem={}
        /** 任务 */
        private task:{[id:number]:number}={}
        constructor() {
            if (Game.Instance) return;
        }

        on(event:string,callback:any,obj:any){           
            this._events[event] = {func:callback,obj:obj};
        }
        off(event:string){            
            if(this._events[event]){
                delete this._events[event];
            }
        }

        /** 获取地图信息 */
        getMapDat(name?: string) {
            var temp = name || this.map;
            return this.mapDat.hasOwnProperty(temp) ? this.mapDat[temp] : null;
        }
        /** 设置地图信息 */
        setMapDat(dat: any, name?: string) {
            var temp = name || this.map;
            this.mapDat[temp] = dat;
        }

        /** 获取团队所有队员 */
        getTeam(){
            return this.team;
        }
        /** 获取背包内所有物品 */
        getPack(){
            return this.pack
        }
        /** 背包内是否有某物品 返回物品数量 */
        isPackItem(itemId:number):boolean{            
            return this.pack.hasOwnProperty(itemId)?true:false;            
        }
        /** 给背包中添加物品 count个 */
        private addPackItem(itemId:number,count:number=1){
            var c = this.pack[itemId]||0;
            var sum = count+c
            this.pack[itemId] = sum;
            if(this._events["packItem"]){
                var qe:QEvent = {
                    name:"add",
                    data:{
                        id:itemId,
                        count:sum
                    }
                }                  
                var func = this._events.packItem.func;
                var obj = this._events.packItem.obj;              
                func.call(obj,qe);              
            }            
        }
        /** 移除背包中某物品N个 */
        private subPackItem(itemId:number,count:number=1){
            var current = this.pack[itemId]-count;
            if(current<=0){
                delete this.pack[itemId];
            }else{
                this.pack[itemId] = current;
            }  
            if(this._events["packItem"]){         
                var qe:QEvent = {
                    name:"sub",
                    data:{
                        id:itemId,
                        count:current
                    }
                }         
                var func = this._events.packItem.func;
                var obj = this._events.packItem.obj;              
                func.call(obj,qe);
            }   
        }
        /** 清空背包中的某物品 */
        private clearPackItem(itemId:number){
            var qe:QEvent = {
                name:"sub",
                data:{
                    id:itemId,
                    count:0
                }
            }  
            delete this.pack[itemId];
            var func = this._events.packItem.func;
            var obj = this._events.packItem.obj;              
            func.call(obj,qe); 
        }
        updatePackItem(packItemDat:Db.PlotDatPack){
            var cmd = packItemDat.cmd;
            var itemId = packItemDat.itemId;
            var number = packItemDat.number||1;
            switch(cmd){
                case "add": //添加物品
                    this.addPackItem(itemId,number);
                break;
                case "sub": //减少一个物品
                    this.subPackItem(itemId,number);
                break;
                case "remove":  //移除所有的物品
                    this.clearPackItem(itemId);
                break;
            }

        }

        /** 接受一个任务 */
        addTask(id){
            if(this.task[id]) return;
            this.task[id] = 1;
            if(this._events["task"]){
                var qe:QEvent = {
                    name:"AddTask",
                    data:{
                        id:id
                    }
                }          
                var func = this._events.task.func;
                var obj = this._events.task.obj;              
                func.call(obj,qe);              
            }             
        }
        /** 获取所有的任务数据 */
        getTaskAll(){
            return this.task;
        }
        /** 是否已接受某任务 */
        isTask(taskId):boolean{
            return this.task.hasOwnProperty(taskId)?true:false;
        }
        /** 更新一个npc的数据 */
        updateNpc(datNpc:Db.PlotDatNpc){    
            //先在地图数据中查找npc
            var mapDat = this.getMapDat(datNpc.map);
            var npcs = mapDat.npc;
            if(datNpc.cmd=="add"){
                //新增一个npc
                return;
            }
            
            var currentNpc:Npc;
            for(var i=0;i<npcs.length;i++){
                var npc = npcs[i];
                if(npc.name==datNpc.name){
                    currentNpc = npc;
                    break;
                }
            }
            if(!currentNpc) return;

            if(datNpc.cmd=="update"){
                //修改一个npc的数据
                if(datNpc.plot){
                    currentNpc.plot = datNpc.plot
                }  
                if(datNpc.needIf){
                    currentNpc.needIf = datNpc.needIf;
                }
            }else if(datNpc.cmd=="delete"){
                //删除一个npc
            }
        }
        /** 更新门的数据 */
        updateDoor(datDoor:Db.PlotDatDoor){
            var mapDat = this.getMapDat(datDoor.map);
            var doors = mapDat.door;
            if(datDoor.cmd=="add"){
                //新增一个门
                return ;
            }
            var currentDoor:Door;
            for(var i=0;i<doors.length;i++){
                var door = doors[i];
                if(door.name==datDoor.name){
                    currentDoor = door;
                    break;
                }
            }
            if(!currentDoor) return;
            if(datDoor.cmd=="update"){
                if(datDoor.door.hasOwnProperty("plot")){
                    currentDoor.plot = datDoor.door.plot;                    
                }                
                if(datDoor.door.hasOwnProperty("isOpen")){                    
                    currentDoor.isOpen = datDoor.door.isOpen;                    
                }                
            }
        }
        /** 提取出保存的数据 */
        toObj(){
            var obj ={
                map:this.map,
                gameTime:this.gameTime,
                mapDat:this.mapDat,
                team:this.team,
                pack:this.pack,
                task:this.task                
            };
            return obj;
        }
        /** 数据还原到game */
        loadObj(obj){
            this.map = obj.map;
            this.gameTime = obj.gameTime;
            this.mapDat = obj.mapDat;
            this.team = obj.team;
            this.pack = obj.pack;
            this.task = obj.task;

            this.door = null;
            this._events = {};
        }
    }
    export let game = new Game();
}